var classLoaderUrl = "/common/util/classLoader.php";
var serviceCallUrl = "/common/classes/serviceCall.php";

//page default gloval var
var GFN_PAGENAVIGATION_VARS = {};
GFN_PAGENAVIGATION_VARS.ROWCOUNT_PER_PAGE = null;	//페이지 내의 최대 로우갯수
GFN_PAGENAVIGATION_VARS.PAGECOUNT_PER_PAGE = null; //화면에 표시할 페이지 갯수
GFN_PAGENAVIGATION_VARS.PAGE_INDEX_PARAM_NAME = "pageIndex";	//서버데이터 통신시 파람네임
GFN_PAGENAVIGATION_VARS.PAGE_SIZE_PARAM_NAME = "pageSize";	//서버데이터 통신시 파람네임
GFN_PAGENAVIGATION_VARS.PAGE_TOTAL_PARAM_NAME = "totalCnt";

/*************************************************************************************
//ServiceCaller의 일반 객체(페이징 없는 Sheet대상)
**************************************************************************************/
var NormalServiceCaller = function(actionId, pagingOptions){
	$.extend(NormalServiceCaller.prototype, AbstractServiceCaller.prototype);	//상속??? 개념을 도입(소스 일원화를 위해!!)
	this._constructFn(actionId, pagingOptions);
};


/*******************************************************
//service caller의 abstractServiceCaller (단독 사용을 금지함)
/************************************************************/
var AbstractServiceCaller = function(){};
AbstractServiceCaller.__serviceStack = {};
//생성자
AbstractServiceCaller.prototype._constructFn = function(serviceId, pagingOptions){	//서비스액션ID, IBSHeaderManager객체
	this.serviceId = serviceId;
	this._searchForm = {};
	this._inputForm = {};
	this._outputForm = {};
	this._inputSheet = {};
	this._inputSheetNm = {};
	this._outputSheet = {};
	this._outputSheetNm = {};
	this.totalPage = 0;
	this.pagingOptions = pagingOptions != ''? true : false;
	this._isAsync = false;
	this.sendType = 'POST';
	this.customSearchValidFunc = null;
	
	this.searchCallback = null;
};

//조회조건 전용 formdata를 bind한다.
AbstractServiceCaller.prototype.searchFormData = function(formId){
	
	this._searchForm[formId] = $("#" + formId);
};

//ajax통신의 async유무를 설정한다.
AbstractServiceCaller.prototype.enableAsync = function(bool){
	/*
	 * 사파리에서 브라우져의 응답 timeout문제를 해결하기 위해 특수한 상황에만 async통신을 하도록 해야한다.
	 * async를 true로 통신할 때는 통신 후 해야할 로직처리에 신중히 신경을 써서 코딩하도록 해야한다.
	 * 반드시 async일때 수행되는 스크립트의 스레드 꼬임을 충분히 이해한 후 접근해야 한다.
	 * 이는 async, sync차이만의 문제가 아니라 콜백 후 콜백함수에서 수행하는 스크립트와 서비스 호출 메서드 밖의 스크립트 수행부분의 연관성을 배제시켜야
	 * 정확하게 작동할 것이다.
	 * 중요한 것은 자바스크립트는 싱글 스레드로만 작동하는 것이 아니라는 것을 꼭 명심해야 한다. 잘못된 코딩을 하면 스크립트 오류도 없고 어떨때는 정상작동하고
	 * 어떨때는 이상하게 작동하는 기묘한 현상이 벌어질 수 있다.
	 * */
	if(bool == true){
		this._isAsync = true;
	}else{
		this._isAsync = false;
	}
};

//검색전용 액션호출 메서드(search form만 가지고 간다)
AbstractServiceCaller.prototype.searchSvc = function(callback, extParam){
	if(!gfn_isEmpty(this.pageNaviObj)){
		this.pageNaviObj.setCurrentPage(1);

		if(!gfn_isEmpty(extParam)){
			for(var key in extParam){
				this.pageNaviObj.param[key] = extParam[key];
			}
		}
	}
	
	if(typeof callback == 'function'){
		this.searchCallback = callback;
	}
	return this.processSvc(callback, extParam);
};

AbstractServiceCaller.prototype.setSendType = function(){
	this.sendType = 'GET';
};
AbstractServiceCaller.prototype.getSendType = function(){
	return this.sendType;
}

//저장전용 액션호출 메서드(바인딩된 모든 데이터를 다 가지고 간다)
AbstractServiceCaller.prototype.processSvc = function(callback, extParam){
	$this = this;
	//파라메터 생성
	var sendData = {};
	sendData.params = extParam;
	sendData.serviceId = this.serviceId;
	//호출 액션주소 조합
	if(typeof sendData.params === 'object'){
		sendData.params = sendData.params;
	}else{
		sendData.params = JSON.stringify(sendData.params);
	}
	

	//ajax option설정
	var ajaxOption = {};
	ajaxOption.url = classLoaderUrl;
	ajaxOption.type = this.getSendType();
	ajaxOption.data = sendData;
	ajaxOption.dataType = "json";
	ajaxOption.success = function(data){
		if(typeof callback === "function"){
			callback(data);
		}
	};
	
	ajaxOption.error = function(){
		alert('error');
	};
	

	//block을 입힌다.
	var jqXHR = $.ajax(ajaxOption);	//데이터 조회와 저장은 양이 큼으로 동기로 통신을 해야한다.
};
//inner func



//page navigation factory
/*
 * option description
 * rowCntPerPage - 페이지내에 최대 로우갯수
 * pageCountPerPage - 화면에 표시할 페이지 갯수
 * indexParamName - 파라미터로 던질 페이지 파라미터 명
 * sizeParamName - 파라미터로 던질 한페이지에 표시할 최대 로우카운트 명
 * */

var PagingNaviFactory = function(targetId, option, callback){
	this.targetId = targetId;
	this.currentPage = 1;			//현재페이지
	this.totalRowCount = option.totalRowCount;	//전체 토탈 카운트
	this.rowCountPerPage;					//페이지내에 최대 로우갯수
	this.pageCountPerPage;					//화면에 표시할 페이지 갯수
	this.firstPerPage;
	this.lastPerPage;
	this.lastPage;
	this.rowCurPos;
	this.rowCountPerPage;
	this.pageCountPerPage;
	this.lastPage;
	this.svcCaller = null;
	this.isShowTotalCnt = true;

	if(gfn_isEmpty(option)){
		option = {};
	}
	this.option = option;
	this.callback = callback;
	this.param = {};
	this.param.pageIndexName = gfn_nvl2(this.option.indexParamName, GFN_PAGENAVIGATION_VARS.PAGE_INDEX_PARAM_NAME);
	this.param.pageSizeName = gfn_nvl2(this.option.sizeParamName, GFN_PAGENAVIGATION_VARS.PAGE_SIZE_PARAM_NAME);
	this.param.totalCntName = gfn_nvl2(this.option.totalCntParamName, GFN_PAGENAVIGATION_VARS.PAGE_TOTAL_PARAM_NAME);

	this._calculatePage();
};

//external func start

//페이지 이동
PagingNaviFactory.prototype.goPage = function(currPage){
	if($("#pageIndex").val() == currPage){
		return;
	}
	
	this.currentPage = currPage;
	$("#pageIndex").val(currPage);
	this.initPageNavi();
	
	if(typeof this.callback === 'function'){
		this.callback();
	}
};

//글목록에 표시할 글번호
PagingNaviFactory.prototype.getPageStartNum = function(){
	console.log(
			"total"+this.totalRowCount+
			"\ncur"+(this.currentPage-1)+
			"\nrowcount_per"+GFN_PAGENAVIGATION_VARS.ROWCOUNT_PER_PAGE
	)
	return this.totalRowCount - (this.currentPage-1) * GFN_PAGENAVIGATION_VARS.ROWCOUNT_PER_PAGE;
};

PagingNaviFactory.prototype.showTotalNum = function(){
	this.isShowTotalCnt = true;
	$("#" + this.targetId).find(".totpgNum").show();
};

PagingNaviFactory.prototype.hideTotalNum = function(){
	this.isShowTotalCnt = false;
	$("#" + this.targetId).find(".totpgNum").hide();
};

//현재 페이지인덱스 반환
PagingNaviFactory.prototype.getCurrentPage = function(){
	return this.currentPage;
};

//현재 페이지인덱스를 설정함
PagingNaviFactory.prototype.setCurrentPage = function(cPage){
	this.currentPage = cPage;
};

//첫 페이지로 이동
PagingNaviFactory.prototype.goFirstPage = function(){
	this.goPage(1);
};

//마지막 페이지로 이동
PagingNaviFactory.prototype.goLastPage = function(){
	this.goPage(this.lastPage);
};

//다음페이지로 이동
PagingNaviFactory.prototype.getNextPage = function(){
	var prvNum = 1;
	if(firstPerPage > __factory.pageCountPerPage){
		prvNum = firstPerPage - 1;
	}

	this.goPage(prvNum);
};

//네비게이션을 새로 그린다.
PagingNaviFactory.prototype.initPageNavi = function(){
	this._calculatePage();
	this._createHtml();
};

//총 데이터건을 설정한다.
PagingNaviFactory.prototype.setTotalCount = function(c){
	this.totalRowCount = c;
};
//external func end

//internal func start

//페이지 내비를 새로 그린다.(내부용)
PagingNaviFactory.prototype._initPaging = function(){
	this._calculatePage();
	this._createHtml();
};

//페이징에 필요한 값들을 계산한다.
PagingNaviFactory.prototype._calculatePage = function(){
	this.rowCurPos = (this.currentPage - 1) * this.rowCountPerPage;
	this.rowCountPerPage = gfn_nvl2(this.option.rowCntPerPage, GFN_PAGENAVIGATION_VARS.ROWCOUNT_PER_PAGE);
	this.pageCountPerPage = gfn_nvl2(this.option.pageCntPerPage, GFN_PAGENAVIGATION_VARS.PAGECOUNT_PER_PAGE);
	this.lastPage = Math.ceil(parseInt(this.totalRowCount) / this.rowCountPerPage);

	this.firstPerPage = Math.ceil(this.getCurrentPage() / this.pageCountPerPage) * this.pageCountPerPage - (this.pageCountPerPage - 1);
	this.lastPerPage = this.firstPerPage + this.pageCountPerPage - 1;
	//console.log(this.firstPerPage +'-'+ this.lastPerPage)
};

PagingNaviFactory.prototype._createHtml = function(){
	// paging Class
	// <<	:	first
	// <	:	prev
	// >	:	next
	// >>	:	last

	var wrapDiv = $("<div/>").addClass("pagenate");
	var wrapRow = $("<p/>").addClass("paging");

	var __factory = this;

	var firstPerPage = this.firstPerPage;
	var lastPerPage = this.lastPerPage;

	var __getSpan = function(text, isSelected, clsNm){
		var rtnObj;
		var buttonObj;
		clsNm = gfn_nvl2(clsNm, false);
		if(clsNm != false){
			buttonObj = $("<button/>").addClass("pagingBtn").addClass(clsNm).attr({type:'button'}).append($("<em/>").text(text));
		}else{
			buttonObj = $("<button/>").attr({type:'button'}).append(text);
		}

		if(isSelected){
			rtnObj = $("<span/>").addClass("selected").append(buttonObj);
		}else{
			rtnObj = $("<span/>").append(buttonObj);
		}
		return rtnObj;
	};

	//prev 버튼
	if(firstPerPage > 1){

		var firstSpan = __getSpan("<<", false, "first");
		firstSpan.click(function(){
			__factory.goPage(1);
		});

		var prevSpan = __getSpan("<", false, "prev");
		prevSpan.click(function(){
			var prvNum = 1;
			if(firstPerPage > __factory.pageCountPerPage){
				prvNum = firstPerPage - 1;
			}
			__factory.goPage( prvNum );
		});

		wrapRow.append(firstSpan).append(prevSpan);
	}

	//페이지 버튼
	for(var i = firstPerPage; i <= lastPerPage; i++){
		if(i <= __factory.lastPage){
			var span = __getSpan(i, (i == __factory.getCurrentPage())? true : false);
			span.data("pageNum", i);

			if(i != __factory.getCurrentPage()){
				span.click(function(){
					__factory.goPage( $(this).data("pageNum") );
				});
			}

			wrapRow.append(span);
		}
	}

	//next 버튼
	if(lastPerPage < __factory.lastPage){
		var nextSpan =  __getSpan(">", false, "next");
		nextSpan.click(function(){
			__factory.goPage( lastPerPage + 1);
		});

		var lastSpan =  __getSpan(">>", false, "last");
		lastSpan.click(function(){
			__factory.goLastPage();
		});
		wrapRow.append(nextSpan).append(lastSpan);
	}

	// total cnt <p> create
	var totRowObj = $("<p/>").addClass("totpgNum");
	var totalText = "[  총  " + __factory.totalRowCount  + " 개 ]";
	totRowObj.append($("<span/>").addClass("fwBold").text(totalText));

	wrapDiv.append(wrapRow);
	wrapDiv.append(totRowObj);

	$("#" + this.targetId).empty();
	$("#" + this.targetId).append(wrapDiv);
	
	if(this.isShowTotalCnt == false){
		this.hideTotalNum();
	}
};


/*****************************************************************************
 * private util성 함수
 * ****************************************************************************/
function __getServiceURL(actionId){
	var ajaxOption = {};
	var serviceInfo = new Array();
	ajaxOption.url = serviceCallUrl;
	ajaxOption.async = false;
	ajaxOption.type = "POST";
	ajaxOption.data = "serviceId="+actionId;
	ajaxOption.success = function(data){
		serviceInfo = data;
	}
	$.ajax(ajaxOption);

	return serviceInfo;
}


/*서비스등록 페이지용*/
var serviceInfo = function(dbjob){
	this.dbjob = dbjob;
};
serviceInfo.prototype.process = function(callback, param){
	var ajaxOption = {};
	var params = {};
	params.dbjob = param.dbjob;
	params.data = param.data;
	ajaxOption.url = "/common/classes/service.php";
	ajaxOption.async = false;
	ajaxOption.type = "POST";
	ajaxOption.data = params;
	ajaxOption.dataType = "json";
	ajaxOption.success = function(data){
		if(typeof callback === 'function'){
			callback(data);
		}
	};
	$.ajax(ajaxOption);
};










